package com.minidb.sql_compiler;

import com.minidb.utils.TokenType;
import java.util.ArrayList;
import java.util.List;

public class LexicalAnalyzer {
    public List<Token> tokenize(String input) {
        List<Token> tokens = new ArrayList<>();
        int line = 1, col = 1;
        boolean inQuote = false;
        char quote = '\0';
        StringBuilder buf = new StringBuilder();
        int tokLine = line, tokCol = col;

        for (int i = 0; i < input.length(); i++) {
            char c = input.charAt(i);

            if (inQuote) {
                if (c == quote) {
                    // 结束字符串
                    tokens.add(new Token(TokenType.CONST_STRING, buf.toString(), tokLine, tokCol));
                    buf.setLength(0);
                    inQuote = false; quote = '\0';
                    col++; // 吸收右引号
                } else {
                    if (c == '\n') { line++; col = 1; } else { col++; }
                    buf.append(c);
                }
                continue;
            }

            if (c == '\'' || c == '"') {
                if (buf.length() > 0) { emitWord(tokens, buf.toString(), tokLine, tokCol); buf.setLength(0); }
                inQuote = true; quote = c; tokLine = line; tokCol = col;
                col++; // 吸收左引号
                continue;
            }

            if (Character.isWhitespace(c)) {
                if (buf.length() > 0) { emitWord(tokens, buf.toString(), tokLine, tokCol); buf.setLength(0); }
                if (c == '\n') { line++; col = 1; } else { col++; }
                continue;
            }

            // 符号类 token - 添加减号支持
            if ("(),;*!=<>-".indexOf(c) >= 0) {
                if (buf.length() > 0) { emitWord(tokens, buf.toString(), tokLine, tokCol); buf.setLength(0); }
                TokenType t = (c == '(' || c == ')' || c == ',' || c == ';' || c == '*')
                        ? TokenType.DELIMITER : TokenType.OPERATOR;
                tokens.add(new Token(t, String.valueOf(c), line, col));
                col++;
                continue;
            }

            // 普通字/数字
            if (buf.length() == 0) { tokLine = line; tokCol = col; }
            buf.append(c);
            col++;
        }

        if (inQuote) throw new IllegalArgumentException(errAt(line, col, "字符串字面量未闭合"));
        if (buf.length() > 0) emitWord(tokens, buf.toString(), tokLine, tokCol);
        tokens.add(new Token(TokenType.EOF, "<EOF>", line, col));
        return tokens;
    }

    private void emitWord(List<Token> out, String s, int line, int col) {
        if (isNumber(s)) {
            out.add(new Token(TokenType.CONST_NUMBER, s, line, col));
        } else if (isIdent(s)) {
            String upper = s.toUpperCase();
            if (isKeyword(upper)) out.add(new Token(TokenType.KEYWORD, upper, line, col));
            else out.add(new Token(TokenType.IDENTIFIER, upper, line, col)); // 统一大写便于比较
        } else {
            throw new IllegalArgumentException(errAt(line, col, "无法识别的词素: " + s));
        }
    }

    private boolean isIdent(String s) {
        if (s.isEmpty()) return false;
        if (!(Character.isLetter(s.charAt(0)) || s.charAt(0) == '_')) return false;
        for (int i=1;i<s.length();i++) {
            char ch = s.charAt(i);
            if (Character.isLetterOrDigit(ch) || ch=='_') continue;
            return false;
        }
        return true;
    }

    private boolean isNumber(String s) {
        if (s.isEmpty()) return false;
        
        // 只处理纯数字和浮点数，负号作为操作符单独处理
        boolean hasDecimalPoint = false;
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            if (ch == '.') {
                if (hasDecimalPoint) return false; // 多个小数点
                if (i == 0 || i == s.length() - 1) return false; // 小数点不能在开头或结尾
                hasDecimalPoint = true;
            } else if (!Character.isDigit(ch)) {
                return false;
            }
        }
        return true;
    }

    private boolean isKeyword(String upper) {
        return switch (upper) {
            case "SELECT","FROM","WHERE","CREATE","TABLE","INSERT","INTO","VALUES","DELETE","NULL","TRUE","FALSE" -> true;
            default -> false;
        };
    }

    private String errAt(int line, int col, String msg) {
        return "词法错误 @(" + line + "," + col + "): " + msg;
    }
}
